package chain

import (
	"context"
	"fmt"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/goccy/go-json"
	"github.com/golang/protobuf/proto"
	tronWallet "github.com/ranjbar-dev/tron-wallet"
	"github.com/ranjbar-dev/tron-wallet/enums"
	"github.com/ranjbar-dev/tron-wallet/grpcClient"
	"github.com/ranjbar-dev/tron-wallet/grpcClient/proto/api"
	"github.com/ranjbar-dev/tron-wallet/grpcClient/proto/core"
	"github.com/ranjbar-dev/tron-wallet/util"
	"go-chain-data/global"
	"go-chain-data/mail"
	"go-chain-data/models"
	"go-chain-data/tools"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
	"golang.org/x/exp/rand"
	"log"
	"math/big"
	"strconv"
	"strings"
	"time"
)

type CrawlTransaction struct {
	TxId          string
	Confirmations int64
	FromAddress   string
	ToAddress     string
	Amount        int64
	Symbol        string
	TokenAddress  string
}

type CrawlResult struct {
	Address      string
	Transactions []CrawlTransaction
}

func SyncBlockToDBTrx() {

	latestBlock := getLast() // 获取数据库中最新的区块信息
	var startNumber int64
	if latestBlock == (models.ScanConfig{}) {
		if global.BlockNumberConfig.Number == "" {
			log.Println("yml文件未配置SettingBlockNumber字段")
			return
		}
		parseInt, err := strconv.ParseInt(global.BlockNumberConfig.Number, 10, 64)
		if err != nil {
			log.Println("blockNumber-string转int64失败:", err)
			return
		}

		var scanConfig models.ScanConfig
		//计算改为自增A
		chainIdInt := uint(global.BlockChainConfig.Id)
		scanConfig.ChainId = chainIdInt
		scanConfig.ChainName = global.BlockChainConfig.Name
		scanConfig.RpcUrl = global.BlockChainConfig.RpcUrl
		scanConfig.LastBlockNumber = uint64(parseInt)
		scanConfig.Type = global.BlockChainConfig.Type
		scanConfig.UdunId = uint64(global.BlockChainConfig.Id)
		err = models.CreateScanConfig(scanConfig)
		if err != nil {
			log.Println("scan_config表insert失败:", err)
			return
		}
	} else {
		startNumber = int64(latestBlock.LastBlockNumber)
		//这里处理一下 如果是上次意外退出 需要先把startNumber这块的数据删除 在扫块
		err := models.DeleteByBlockNumber(startNumber)
		wai := models.WatchAddressInfo{}
		// 删除watch_address_info表
		err = wai.DeleteByBlockNumber(startNumber)
		if err != nil {
			log.Println("删除失败", err)
			return
		}
	}

	node := enums.CreateNode(global.BlockChainConfig.RpcUrl)
	//node := enums.CreateNode("grpc.trongrid.io:50051")
	client, err := grpcClient.GetGrpcClient(node)
	if err != nil {
		log.Printf("Error getting TRX client: %v", err)
		return
	}

	scanClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("scan_config")
	filter := bson.D{{"rpcUrl", global.BlockChainConfig.RpcUrl}, {"chainId", global.BlockChainConfig.Id}, {"chainName", global.BlockChainConfig.Name}, {"type", global.BlockChainConfig.Type}}

	for {
		result := scanClient.FindOne(context.Background(), filter)
		if err := result.Err(); err != nil {
			log.Printf("Error getting TRX scanConfig: %v", err)
			continue
		}
		var scanConfig models.ScanConfig
		err = result.Decode(&scanConfig)
		if err != nil {
			log.Printf("Error decoding TRX scanConfig: %v", err)
			continue
		}

		// 从数据库中获取最后处理的区块号
		lastProcessed := scanConfig.LastBlockNumber
		lastProcessedBlock := new(big.Int)
		lastProcessedBlock = lastProcessedBlock.SetUint64(lastProcessed)
		addressList, err := FetchAddressesFromDB(uint(global.BlockChainConfig.Id), global.BlockChainConfig.Name)
		if err != nil {
			log.Printf("Error getting Trx addressList: %v", err)
			continue
		}
		c := &tronWallet.Crawler{
			//Node:      enums.CreateNode(chainConfig.RrcUrls[0].Url),
			Node:      node,
			Addresses: addressList,
		}
		block, err := client.GetNowBlock()
		if err != nil {
			log.Printf("Error getting TRX last blocknumber: %v", err)
			continue
		}
		currentBlock := big.NewInt(block.BlockHeader.RawData.Number)

		if lastProcessedBlock.Cmp(currentBlock) < 0 {

			//此处怕扫太快交易还没有被确认 导致没有归集
			if currentBlock.Cmp(lastProcessedBlock) == 2 {
				time.Sleep(1 * time.Second)
			}

			// 更新最后处理的区块号并保存到数据库
			addNum := big.NewInt(lastProcessedBlock.Int64())
			addNum.Add(addNum, big.NewInt(1))
			if addNum.Cmp(currentBlock) > 0 {
				addNum = currentBlock
			}

			//计算改为自增A
			scanConfig.LastBlockNumber = addNum.Uint64()
			err = models.CreateScanConfig(scanConfig)
			if err != nil {
				log.Println("scan_config表insert失败:", err)
				continue
			}

			//currentBlock 转 int64
			currentBlockInt64 := addNum.Int64()
			block, err := client.GetBlockByNum(currentBlockInt64)
			if err != nil {
				fmt.Println(err)
				continue
			}

			log.Printf("开始，当前区块高度: %d", currentBlockInt64)
			txs := getTransaction(block, currentBlockInt64, c, node)
			log.Printf("结束，当前区块高度: %d  数量： %d", currentBlockInt64, len(txs))
			if len(txs) > 0 {
				go func() {
					for _, l := range txs {
						fmt.Println("l.Amount:", l.Amount)
						if l.Amount < 1000000 {
							log.Printf("涉嫌欺诈的交易 %s", l.TxId)
							continue
						}

						//t, _ := json.Marshal(l)
						//fmt.Println(string(t), "987")
						log.Printf("进TRX充币")

						//去重复操作
						upCoinClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("up_coin")
						documents, _ := upCoinClient.CountDocuments(context.Background(), bson.M{"txHash": l.TxId})
						if documents != 0 {
							log.Printf("trx重复: %v", l.TxId)
							continue
						}
						fmt.Println("l.Symbol", l.Symbol)
						fmt.Println("l.tokenAddress", l.TokenAddress)
						tokenInfo, err := models.GetUserTokenInfoByAddress(l.TokenAddress)
						if err != nil {
							log.Printf("TRX充币监控，获取token详情失败 %s", err.Error())
							continue
						}

						//查询用户apikey
						var addressModel models.WatchAddressConfig
						addressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
						err = addressClient.FindOne(context.Background(), bson.M{"address": l.ToAddress}).Decode(&addressModel)
						if err != nil {
							log.Printf("TRX充币监控，查找用户地址详情失败 %s", err.Error())
							continue
						}
						var user models.User
						userClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user")
						objId, _ := primitive.ObjectIDFromHex(addressModel.UserId)
						err = userClient.FindOne(context.TODO(), bson.M{"_id": objId}).Decode(&user)
						if err != nil {
							log.Printf("TRX充币监控，查找用户详情失败 %s", err.Error())
							continue
						}

						var UserPrivatekeys models.UserPrivateKey
						keyClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
						err = keyClient.FindOne(context.Background(), bson.M{"userId": user.Id, "mainCoinType": scanConfig.UdunId}).Decode(&UserPrivatekeys)
						if err != nil {
							log.Printf("Failed to get private key: %s", err)
							continue
						}

						if UserPrivatekeys.FeeAddress == l.FromAddress {
							log.Printf("手续费 非充币")
							continue
						}

						divisor := big.NewInt(10).Exp(big.NewInt(10), big.NewInt(int64(tokenInfo.Decimals)), nil)
						dividendBig, _ := new(big.Int).SetString(strconv.FormatInt(l.Amount, 10), 10)
						expression := new(big.Rat).SetInt(dividendBig).Quo(new(big.Rat).SetInt(dividendBig), new(big.Rat).SetInt(divisor))
						resultFloat, _ := expression.Float64()
						quotient := strconv.FormatFloat(resultFloat, 'f', -1, 64)

						var upCoin models.UpCoin
						upCoin.Data = ""
						upCoin.BlockHash = ""
						upCoin.TxHash = l.TxId
						upCoin.From = l.FromAddress
						upCoin.To = l.ToAddress
						upCoin.Value = quotient
						upCoin.Timestamp = uint(time.Now().Unix())
						upCoin.BlockNumber = uint(lastProcessedBlock.Uint64())
						upCoin.TokenAddress = tokenInfo.Address
						upCoin.ChainId = uint(global.BlockChainConfig.Id)
						upCoin.ChainName = global.BlockChainConfig.Name
						upCoin.SymbolName = tokenInfo.Symbol
						upCoin.UserId = user.Id
						upCoin.Status = 1
						upCoin.ChainName = global.BlockChainConfig.Name
						upCoin.SymbolName = tokenInfo.Symbol
						upCoin.BlockNumber = uint(currentBlock.Uint64())
						upCoinId, err := upCoinClient.InsertOne(context.Background(), upCoin)
						if err != nil {
							log.Printf("TRX充币监控，插入充币记录失败 %s", err.Error())
							continue
						}

						if tokenInfo.MinAmount != 0 && resultFloat < tokenInfo.MinAmount {
							_, err = upCoinClient.UpdateOne(context.Background(), bson.M{"_id": upCoinId.InsertedID.(primitive.ObjectID)}, bson.M{"$set": bson.M{"status": 2}})
							if err != nil {
								log.Printf("更新数据error:%s,id:%s", err, upCoinId.InsertedID.(primitive.ObjectID).Hex())
							}
							log.Printf("当前用户 %s 的最小归集钱数 %f 小于交易金额 %f", user.Id, tokenInfo.MinAmount, resultFloat)
							continue
						}

						if user.MaturityTime == 0 || user.Status == 0 {
							log.Printf("会员已过期，不进行归集操作")
							_, err = upCoinClient.UpdateOne(context.Background(), bson.M{"_id": upCoinId.InsertedID.(primitive.ObjectID)}, bson.M{"$set": bson.M{"status": 0}})
							if err != nil {
								log.Printf("会员到期更新数据:%s,id:%s", err, upCoinId.InsertedID.(primitive.ObjectID).Hex())
							}
							continue
						}

						//2 callback发射
						//构建body
						var body models.CallBackBody
						body.Address = upCoin.To
						body.Amount = upCoin.Value
						body.Fee = 0
						//查询币种精度
						body.Decimals = int(tokenInfo.Decimals)
						//body.CoinType = strconv.Itoa(int(tokenInfo.ID))
						//body.MainCoinType = strconv.Itoa(int(chainConfig.ID))
						body.CoinType = tokenInfo.Address
						body.MainCoinType = strconv.FormatUint(scanConfig.UdunId, 10)
						body.BusinessId = ""
						body.BlockHigh = strconv.Itoa(int(upCoin.BlockNumber))
						body.Status = 3
						body.TradeId = upCoin.ID.Hex()
						body.TradeType = 1
						body.TxId = upCoin.TxHash
						body.Memo = ""

						rand.Seed(uint64(time.Now().UnixNano())) // 初始化随机数种子
						randomInt := rand.Intn(10000000)         // 生成一个0到99的随机整数

						//回调的请求数据数据
						userApiKey := user.ApiKey
						randomString := strconv.Itoa(randomInt)
						timestamp := strconv.FormatInt(time.Now().Unix(), 10)
						sign, err := tools.GetSign(&body, userApiKey, randomString, timestamp)
						var RequestData models.RequestData
						RequestData.Body = body
						RequestData.Nonce = randomString
						RequestData.Timestamp = timestamp
						RequestData.Sign = sign
						RequestData.UserApikey = userApiKey
						RequestDataStr, err := json.Marshal(RequestData)
						if err != nil {
							log.Printf("充币监控，回调数据转json失败 %s", err.Error())
							continue
						}

						var callBackData models.CollectionCallback
						callBackData.ChainName = global.BlockChainConfig.Name
						callBackData.ChainId = uint(global.BlockChainConfig.Id)
						callBackData.BlockNumber = lastProcessedBlock.Uint64()
						callBackData.TxHash = l.TxId
						callBackData.From = l.FromAddress
						callBackData.To = l.ToAddress
						callBackData.Token = tokenInfo.Address
						callBackData.Amount = quotient
						callBackData.CallBackUrl = addressModel.CallBackUrl
						callBackData.Verify = 0
						callBackData.CallBackTime = time.Now().Unix()
						callBackData.RequestData = string(RequestDataStr)
						callBackData.SymbolName = tokenInfo.Symbol
						callBackData.ToAddress = upCoin.To
						callBackData.UserId = user.Id
						insertedId, err := global.DBEngine.Database(global.DbConfig.DbName).Collection("collection_callback").InsertOne(context.Background(), callBackData)
						if err != nil {
							log.Printf("inserted failed to collection_callback table: %s", err.Error())
							continue
						}

						//发送post
						go func() {
							defer func() {
								if r := recover(); r != nil {
									fmt.Println("Recovered from", r)
								}
							}()
							err := tools.SendCallBackV2(&body, sign, randomString, timestamp, addressModel.CallBackUrl, insertedId.InsertedID.(primitive.ObjectID))
							if err != nil {
								log.Printf("TRX充币监控，callback发送失败 %s", err.Error())
							}
						}()
						//3当场归集
						//计算手续费

						//a, err := tronWallet.CreateTronWallet(c.Node, addressModel.PrivateKey)
						//if err != nil {
						//	log.Printf("TRX充币监控，创建转账钱包失败 %s", err.Error())
						//	continue
						//}
						//f, err := tronWallet.CreateTronWallet(c.Node, UserPrivatekeys.FeeAddress)
						//if err != nil {
						//	log.Printf("TRX充币监控，创建手续费钱包失败 %s", err.Error())
						//	continue
						//}
						if l.Symbol == "TRX" {

							//主币转账
							//估算gas费
							//feeInSun, err := a.EstimateTransferFee(UserPrivatekeys.CollectAddress, l.Amount)
							//if err != nil {
							//	log.Printf("TRX充币监控，预估手续费失败 %s", err.Error())
							//	continue
							//}
							//转手续费
							txId, err := tools.GetTrxTransactionSign(l.ToAddress, "2000000", "", UserPrivatekeys.FeeBusinessId, scanConfig.RpcUrl)
							//txId, err := f.Transfer(l.ToAddress, feeInSun)
							if err != nil {
								log.Printf("TRX充币监控，手续费转账失败 %s", err.Error())
								_, err = upCoinClient.UpdateOne(context.Background(), bson.M{"_id": upCoinId.InsertedID.(primitive.ObjectID)}, bson.M{"$set": bson.M{"status": 2}})
								str := "尊敬的BlockWatch会员：\n\n您好！\n\n您的" + global.BlockChainConfig.Name + "链下的手续费私钥余额不足,导致了本次归集失败,请尽快补充公链币,以免影响后续归集.\nDear BlockWatch Member,Your" + global.BlockChainConfig.Name + "chain transaction fee private key balance is insufficient, resulting in a failed collection attempt. Please replenish your public chain coins as soon as possible to avoid affecting subsequent collections."
								emailParams := mail.Options{
									MailHost: global.EmailConfig.Host,
									MailPort: global.EmailConfig.Port,
									MailUser: global.EmailConfig.User,
									MailPass: global.EmailConfig.Password,
									MailTo:   user.Email,
									Subject:  "提币操作提醒",
									Body:     str,
								}
								mail.Send(&emailParams)

								time.Sleep(2 * time.Second)
								continue
							}
							log.Printf("fee地址分配手续费成功: %s", txId)
							//等待手续费到账
							time.Sleep(20 * time.Second)
							//进行归集操作
							//txId2, err := a.Transfer(UserPrivatekeys.CollectAddress, l.Amount)

							txId2, err := tools.GetTrxTransactionSign(UserPrivatekeys.CollectAddress, strconv.FormatInt(l.Amount, 10), "", addressModel.BusinessId, scanConfig.RpcUrl)

							if err != nil {
								log.Printf("TRX充币监控，归集失败 %s", err.Error())
								continue
							}
							log.Printf("归集发送成功成功: %s", txId2)

							_, err = upCoinClient.UpdateOne(context.Background(), bson.M{"_id": upCoinId.InsertedID.(primitive.ObjectID)}, bson.M{"$set": bson.M{"status": 1}})
							if err != nil {
								log.Printf("EVM主币充币监控，更新%s状态失败  %s", upCoinId, err.Error())
								continue
							}

							log.Printf("EVM主币充币监控，更新状态成功")
						} else {

							txId, err := tools.GetTrxTransactionSign(l.ToAddress, "30000000", "", UserPrivatekeys.FeeBusinessId, scanConfig.RpcUrl)
							//转手续费
							//txId, err := f.Transfer(l.ToAddress, 30000000)
							if err != nil {
								log.Printf("TRX充币监控，手续费转账失败 %s", err.Error())
								_, err = upCoinClient.UpdateOne(context.Background(), bson.M{"_id": upCoinId.InsertedID.(primitive.ObjectID)}, bson.M{"$set": bson.M{"status": 2}})
								str := "尊敬的BlockWatch会员：\n\n您好！\n\n您的" + global.BlockChainConfig.Name + "链下的手续费私钥余额不足,导致了本次归集失败,请尽快补充公链币,以免影响后续归集.\nDear BlockWatch Member,Your" + global.BlockChainConfig.Name + "chain transaction fee private key balance is insufficient, resulting in a failed collection attempt. Please replenish your public chain coins as soon as possible to avoid affecting subsequent collections."
								emailParams := mail.Options{
									MailHost: global.EmailConfig.Host,
									MailPort: global.EmailConfig.Port,
									MailUser: global.EmailConfig.User,
									MailPass: global.EmailConfig.Password,
									MailTo:   user.Email,
									Subject:  "提币操作提醒",
									Body:     str,
								}
								mail.Send(&emailParams)
								continue
							}
							log.Printf("fee地址分配手续费成功: %s", txId)
							//等待手续费到账
							time.Sleep(20 * time.Second)
							//进行归集操作
							//token := &tronWallet.Token{
							//	ContractAddress: enums.CreateContractAddress(tokenInfo.Address),
							//}
							//txId2, err := a.TransferTRC20(token, UserPrivatekeys.CollectAddress, l.Amount)
							txId2, err := tools.GetTrxTransactionSign(UserPrivatekeys.CollectAddress, strconv.FormatInt(l.Amount, 10), tokenInfo.Address, addressModel.BusinessId, scanConfig.RpcUrl)
							if err != nil {
								log.Printf("TRX充币监控，归集失败 %s", err.Error())
								continue
							}
							log.Printf("归集发送成功成功: %s", txId2)

							_, err = upCoinClient.UpdateOne(context.Background(), bson.M{"_id": upCoinId.InsertedID.(primitive.ObjectID)}, bson.M{"$set": bson.M{"status": 1}})
							if err != nil {
								log.Printf("EVM主币充币监控，更新%s状态失败  %s", upCoinId.InsertedID.(string), err.Error())
								continue
							}
						}

					}
				}()
			}
		}
		time.Sleep(1 * time.Second)
	}
}

func getTransaction(block *api.BlockExtention, currentBlock int64, c *tronWallet.Crawler, node enums.Node) []CrawlTransaction {
	var txs []CrawlTransaction

	for _, t := range block.Transactions {

		transaction := t.Transaction
		// if transaction is not success 智能合约调用Ret才会有值
		if len(transaction.Ret) != 0 && transaction.Ret[0].ContractRet != core.Transaction_Result_SUCCESS {
			//log.Println("transaction is not success", transaction.Ret[0].ContractRet)
			continue
		}

		// if transaction is not tron transfer or erc20 transfer
		if transaction.RawData.Contract[0].Type != core.Transaction_Contract_TransferContract && transaction.RawData.Contract[0].Type != core.Transaction_Contract_TriggerSmartContract {
			//log.Println("transaction is not tron transfer or erc20 transfer", transaction.RawData.Contract[0].Type)
			continue
		}

		var crawlTransaction *CrawlTransaction = nil

		if transaction.RawData.Contract[0].Type == core.Transaction_Contract_TransferContract {
			contract := &core.TransferContract{}
			err := proto.Unmarshal(transaction.RawData.Contract[0].Parameter.Value, contract)
			if err != nil {
				log.Println("error", err)
				continue
			}

			status := false
			for _, ourAddress := range c.Addresses {
				address, _ := util.Base58ToAddress(ourAddress)
				toAddress := hexutil.Encode(contract.ToAddress)
				if strings.ToUpper(toAddress) == strings.ToUpper(address.Hex()) {
					status = true
					log.Println("main match address success")
					break
				}
			}
			if status {
				crawlTransaction = prepareTrxTransaction(t, contract)
			}

		} else if transaction.RawData.Contract[0].Type == core.Transaction_Contract_TriggerSmartContract {
			contract := &core.TriggerSmartContract{}
			err := proto.Unmarshal(transaction.RawData.Contract[0].Parameter.Value, contract)
			if err != nil {
				fmt.Println("error", err)
				continue
			}

			tokenTransferData, _ := util.ParseTrc20TokenTransfer(util.ToHex(contract.Data)[2:])
			toAddress := tokenTransferData.To
			status := false
			for _, ourAddress := range c.Addresses {
				if strings.ToUpper(toAddress) == strings.ToUpper(ourAddress) {
					status = true
					log.Println("token match address success", toAddress)
					break
				}
			}
			if status {
				crawlTransaction = prepareTrc20Transaction(t, contract, node)
			}
		}

		if crawlTransaction != nil && currentBlock != 0 {
			crawlTransaction.Confirmations = currentBlock - block.BlockHeader.RawData.Number
		}

		if crawlTransaction != nil {
			log.Println("find transaction success", crawlTransaction)
			txs = append(txs, *crawlTransaction)
		}

	}
	return txs
}

func prepareTrxTransaction(t *api.TransactionExtention, contract *core.TransferContract) *CrawlTransaction {

	// if address is hex convert to base58
	toAddress := hexutil.Encode(contract.ToAddress)[2:]
	if strings.HasPrefix(toAddress, "41") == true {
		toAddress = util.HexToAddress(toAddress).String()
	}
	log.Println("toAddress", toAddress)

	// if address is hex convert to base58
	fromAddress := hexutil.Encode(contract.OwnerAddress)[2:]
	if strings.HasPrefix(fromAddress, "41") == true {
		fromAddress = util.HexToAddress(fromAddress).String()
	}
	log.Println("fromAddress", fromAddress)

	return &CrawlTransaction{
		TxId:         hexutil.Encode(t.GetTxid())[2:],
		FromAddress:  fromAddress,
		ToAddress:    toAddress,
		Amount:       contract.Amount,
		Symbol:       "TRX",
		TokenAddress: "648126",
	}
}

func prepareTrc20Transaction(t *api.TransactionExtention, contract *core.TriggerSmartContract, node enums.Node) *CrawlTransaction {

	tokenTransferData, validTokenData := util.ParseTrc20TokenTransfer(util.ToHex(contract.Data)[2:])
	fmt.Println("validTokenData", validTokenData)
	if validTokenData == false {
		return nil
	}

	// if contractAddress is hex convert to base58
	contractAddress := hexutil.Encode(contract.ContractAddress)[2:]
	if strings.HasPrefix(contractAddress, "41") == true {
		contractAddress = util.HexToAddress(contractAddress).String()
	}
	fmt.Println("contractAddress", contractAddress)

	// if address is hex convert to base58
	toAddress := tokenTransferData.To
	if strings.HasPrefix(toAddress, "41") == true {
		toAddress = util.HexToAddress(toAddress).String()
	}
	fmt.Println("toAddress", toAddress)

	// if address is hex convert to base58
	fromAddress := hexutil.Encode(contract.OwnerAddress)[2:]
	if strings.HasPrefix(fromAddress, "41") == true {
		fromAddress = util.HexToAddress(fromAddress).String()
	}
	fmt.Println("fromAddress", fromAddress)

	token := &tronWallet.Token{
		ContractAddress: enums.CreateContractAddress(contractAddress),
	}
	symbol, _ := token.GetSymbol(node, fromAddress)
	fmt.Println("symbol", symbol)
	fmt.Println("TxId", hexutil.Encode(t.GetTxid())[2:])

	return &CrawlTransaction{
		TxId:         hexutil.Encode(t.GetTxid())[2:],
		FromAddress:  fromAddress,
		ToAddress:    toAddress,
		Amount:       tokenTransferData.Value.Int64(),
		Symbol:       symbol,
		TokenAddress: contractAddress,
	}
}

// getUpCoinAddress  获取所有TRX的地址集合
func getUpCoinAddress(chainID uint, chainName string) ([]string, error) {
	var tokenAddressListStruct []*models.WatchAddressConfig
	addressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	find, err := addressClient.Find(context.Background(), bson.D{{"chainId", chainID}, {"chainName", chainName}, {"type", "udun"}})
	if err != nil {
		log.Printf("TRX充币监控，获取address列表失败 %s", err.Error())
		return nil, err
	}
	err = find.All(context.Background(), &tokenAddressListStruct)
	if err != nil {
		log.Printf("TRX充币监控，解析数据失败 %s", err.Error())
		return nil, err
	}

	var addressList []string
	for _, token := range tokenAddressListStruct {
		addressList = append(addressList, token.Address)
	}
	return addressList, nil
}

func GetUpCoinAddress(chainID uint, chainName string) ([]string, error) {
	var tokenAddressListStruct []*models.WatchAddressConfig
	addressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	find, err := addressClient.Find(context.Background(), bson.D{{"chainId", chainID}, {"chainName", chainName}, {"type", "udun"}})
	if err != nil {
		log.Printf("TRX充币监控，获取address列表失败 %s", err.Error())
		return nil, err
	}
	err = find.All(context.Background(), &tokenAddressListStruct)
	if err != nil {
		log.Printf("TRX充币监控，解析数据失败 %s", err.Error())
		return nil, err
	}

	var addressList []string
	for _, token := range tokenAddressListStruct {
		addressList = append(addressList, token.Address)
	}
	return addressList, nil
}

func FetchAddressesFromDB(chainID uint, chainName string) ([]string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	collection := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")

	// 只查询address字段
	opts := options.Find().SetProjection(bson.M{"address": 1, "_id": 0})

	cur, _ := collection.Find(ctx, bson.M{
		"chainId":   chainID,
		"chainName": chainName,
		"type":      "udun",
	}, opts)

	// ...错误处理同上...

	// 直接流式处理游标
	var addresses []string
	for cur.Next(ctx) {
		var doc struct {
			Address string `bson:"address"`
		}
		if err := cur.Decode(&doc); err == nil {
			addresses = append(addresses, doc.Address)
		}
	}
	return addresses, cur.Err()
}
